home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume26 / tclx / part19 < prev    next >
Encoding:
Text File  |  1991-11-19  |  43.5 KB  |  1,460 lines

  1. Newsgroups: comp.sources.misc
  2. From: karl@sugar.neosoft.com (Karl Lehenbauer)
  3. Subject:  v26i019:  tclx - extensions and on-line help for tcl 6.1, Part19/23
  4. Message-ID: <1991Nov19.135655.1468@sparky.imd.sterling.com>
  5. X-Md4-Signature: 45fe6fdcb81989298d1a1319a2b0f430
  6. Date: Tue, 19 Nov 1991 13:56:55 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: karl@sugar.neosoft.com (Karl Lehenbauer)
  10. Posting-number: Volume 26, Issue 19
  11. Archive-name: tclx/part19
  12. Environment: UNIX
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 19 (of 23)."
  21. # Contents:  extended/src/list.c extended/src/signal.c
  22. # Wrapped by karl@one on Wed Nov 13 21:50:31 1991
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'extended/src/list.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'extended/src/list.c'\"
  26. else
  27. echo shar: Extracting \"'extended/src/list.c'\" \(19858 characters\)
  28. sed "s/^X//" >'extended/src/list.c' <<'END_OF_FILE'
  29. X/* 
  30. X * list.c --
  31. X *
  32. X *      TCL extend list commands.
  33. X *---------------------------------------------------------------------------
  34. X * Copyright 1991 Karl Lehenbauer and Mark Diekhans.
  35. X *
  36. X * Permission to use, copy, modify, and distribute this software and its
  37. X * documentation for any purpose and without fee is hereby granted, provided
  38. X * that the above copyright notice appear in all copies.  Karl Lehenbauer and
  39. X * Mark Diekhans make no representations about the suitability of this
  40. X * software for any purpose.  It is provided "as is" without express or
  41. X * implied warranty.
  42. X */
  43. X
  44. X#include "tclExtdInt.h"
  45. X
  46. X/*
  47. X * Prototypes of internal functions.
  48. X */
  49. Xint
  50. XCompareKeyListField _ANSI_ARGS_((Tcl_Interp   *interp,
  51. X                                 char         *fieldName,
  52. X                                 char         *field,
  53. X                                 char        **valuePtr,
  54. X                                 int          *valueSizePtr));
  55. X
  56. Xint
  57. XFindKeyListField _ANSI_ARGS_((Tcl_Interp  *interp,
  58. X                              char        *fieldName,
  59. X                              int          listArgc,
  60. X                              char       **listArgv,
  61. X                              int         *listIdxPtr));
  62. X
  63. Xint
  64. XTcl_GetKeyedListField _ANSI_ARGS_((Tcl_Interp  *interp,
  65. X                                   CONST char  *fieldName,
  66. X                                   CONST char  *keyedList,
  67. X                                   char       **fieldValuePtr));
  68. X
  69. Xchar *
  70. XTcl_SetKeyedListField _ANSI_ARGS_((Tcl_Interp  *interp,
  71. X                                   CONST char  *fieldName,
  72. X                                   CONST char  *fieldvalue,
  73. X                                   CONST char  *keyedList));
  74. X
  75. Xchar *
  76. XTcl_DeleteKeyedListField _ANSI_ARGS_((Tcl_Interp  *interp,
  77. X                                      CONST char  *fieldName,
  78. X                                      CONST char  *keyedList));
  79. X
  80. X/*
  81. X *----------------------------------------------------------------------
  82. X *
  83. X * CompareKeyListField --
  84. X *   Compare a field name to a field (keyword/value pair) to determine if
  85. X * the field names match.
  86. X *
  87. X * Parameters:
  88. X *   o interp (I/O) - Error message will be return in result if there is an
  89. X *     error.
  90. X *   o fieldName (I) - Field name to compare against field.
  91. X *   o field (I) - Field to see if its name matches.
  92. X *   o valuePtr (O) - If the field names match, a pointer to value part is
  93. X *     returned.
  94. X *   o valueSizePtr (O) - If the field names match, the length of the value
  95. X *     part is returned here.
  96. X * Results:
  97. X *    TCL_OK - If the field names match.
  98. X *    TCL_BREAK - If the fields names don't match.
  99. X *    TCL_ERROR -  If the list has an invalid format.
  100. X *----------------------------------------------------------------------
  101. X */
  102. Xstatic int
  103. XCompareKeyListField (interp, fieldName, field, valuePtr, valueSizePtr)
  104. X    Tcl_Interp   *interp;
  105. X    char         *fieldName;
  106. X    char         *field;
  107. X    char        **valuePtr;
  108. X    int          *valueSizePtr; 
  109. X{
  110. X    char *elementPtr, *nextPtr;
  111. X    int   fieldNameSize, elementSize;
  112. X
  113. X    if (field [0] == '\0') {
  114. X        Tcl_AppendResult (interp, "invalid keyed list format: ",
  115. X                          "list contains an empty field entry",
  116. X                          (char *) NULL);
  117. X        return TCL_ERROR;
  118. X    }
  119. X    if (TclFindElement (interp, field, &elementPtr, &nextPtr, 
  120. X                        &elementSize, NULL) != TCL_OK)
  121. X        return TCL_ERROR;
  122. X    if (elementSize == 0) {
  123. X        Tcl_AppendResult (interp, "invalid keyed list format: ",
  124. X                          "list contains an empty field name",
  125. X                          (char *) NULL);
  126. X        return TCL_ERROR;
  127. X    }
  128. X    if (nextPtr[0] == '\0') {
  129. X        Tcl_AppendResult (interp, "invalid keyed list format: ",
  130. X                          "no value associated with field \"",
  131. X                          elementPtr, "\"", (char *) NULL);
  132. X        return TCL_ERROR;
  133. X    }
  134. X
  135. X    fieldNameSize = strlen (fieldName);
  136. X    if (!((elementSize == fieldNameSize) && 
  137. X            STRNEQU (elementPtr, fieldName, fieldNameSize)))
  138. X        return TCL_BREAK;   /* Names do not match */
  139. X
  140. X    /*
  141. X     * Extract the value from the list.
  142. X     */
  143. X    if (TclFindElement (interp, nextPtr, &elementPtr, &nextPtr, &elementSize, 
  144. X                        NULL) != TCL_OK)
  145. X        return TCL_ERROR;
  146. X    if (nextPtr[0] != '\0') {
  147. X        Tcl_AppendResult (interp, "invalid keyed list format: ",
  148. X                          "trailing data following value in field: \"",
  149. X                          elementPtr, "\"", (char *) NULL);
  150. X        return TCL_ERROR;
  151. X    }
  152. X    *valuePtr = elementPtr;
  153. X    *valueSizePtr = elementSize;
  154. X    return TCL_OK;
  155. X}
  156. X
  157. X/*
  158. X *----------------------------------------------------------------------
  159. X *
  160. X * FindKeyListField --
  161. X *   Locate a field (key/value pair) in a key list that has been broken
  162. X * into an argv.
  163. X *
  164. X * Parameters:
  165. X *   o interp (I/O) - Error message will be return in result if there is an
  166. X *     error.
  167. X *   o fieldName (I) - The name of the field to find, should have all 
  168. X *     subsequent parts (seperated by `.'), the pointer to the next part will
  169. X *     be returned as part of the parseResult.
  170. X *   o listArgc/listArgv (I) - The keyed list, split into an argv.
  171. X *   o listIdxPtr (O) - The argv index containing the list entry that matches
  172. X *     the field name, or -1 if the key was not found.
  173. X * Results:
  174. X *   Standard Tcl result.
  175. X *----------------------------------------------------------------------
  176. X */
  177. Xstatic int
  178. XFindKeyListField (interp, fieldName, listArgc, listArgv, listIdxPtr)
  179. X    Tcl_Interp  *interp;
  180. X    char        *fieldName;
  181. X    int          listArgc;
  182. X    char       **listArgv;
  183. X    int         *listIdxPtr;
  184. X{
  185. X    int   idx, result, valueSize;
  186. X    char *value;
  187. X
  188. X    for (idx = 0; idx < listArgc; idx++) {
  189. X        result = CompareKeyListField (interp, fieldName, listArgv [idx],
  190. X                                      &value, &valueSize);
  191. X        if (result != TCL_BREAK)
  192. X            break;  /* Found or error */
  193. X    }
  194. X    if (result == TCL_ERROR)
  195. X        return TCL_ERROR;
  196. X    if (idx >= listArgc)
  197. X        *listIdxPtr = -1;  /* Not found */
  198. X    else
  199. X        *listIdxPtr = idx;
  200. X    return TCL_OK;
  201. X}
  202. X
  203. X/*
  204. X *----------------------------------------------------------------------
  205. X *
  206. X * Tcl_GetKeyedListField --
  207. X *   Retrieve a field value from a keyed list.  The list is walked rather than
  208. X * converted to a argv for increased performance.
  209. X *
  210. X * Parameters:
  211. X *   o interp (I/O) - Error message will be return in result if there is an
  212. X *     error.
  213. X *   o fieldName (I) - The name of the field to extract.
  214. X *   o keyedList (I) - The list to search for the field.
  215. X *   o fieldValuePtr (O) - If the field is found, a pointer to a dynamicly
  216. X *     allocated string containing the value is returned here.  If NULL is
  217. X *     specified, then only the presence of the field is validated, the
  218. X *     value is not returned.
  219. X * Results:
  220. X *   TCL_OK - If the field was found.
  221. X *   TCL_BREAK - If the field was not found.
  222. X *   TCL_ERROR - If an error occured.
  223. X *----------------------------------------------------------------------
  224. X */
  225. Xint
  226. XTcl_GetKeyedListField (interp, fieldName, keyedList, fieldValuePtr)
  227. X    Tcl_Interp  *interp;
  228. X    CONST char  *fieldName;
  229. X    CONST char  *keyedList;
  230. X    char       **fieldValuePtr;
  231. X{
  232. X    char *scanPtr;
  233. X    char *value;
  234. X    int   valueSize, result;
  235. X
  236. X    /*
  237. X     * Walk the list looking for a field name that matches.
  238. X     */
  239. X    scanPtr = (char *) keyedList;
  240. X    result = TCL_OK;
  241. X    while (*scanPtr != '\0') {
  242. X        char *fieldPtr;
  243. X        int   fieldSize;
  244. X        char  saveChar;
  245. X
  246. X        result = TclFindElement (interp, scanPtr, &fieldPtr, &scanPtr, 
  247. X                                 &fieldSize, NULL);
  248. X        if (result != TCL_OK)
  249. X            break;
  250. X
  251. X        saveChar = fieldPtr [fieldSize];
  252. X        fieldPtr [fieldSize] = '\0';
  253. X
  254. X        result = CompareKeyListField (interp, (char *) fieldName, fieldPtr,
  255. X                                      &value, &valueSize);
  256. X        fieldPtr [fieldSize] = saveChar;
  257. X        if (result != TCL_BREAK)
  258. X            break;  /* Found or an error */
  259. X    }
  260. X
  261. X    if (result != TCL_OK)
  262. X        return result;   /* Not found or an error */
  263. X
  264. X    if (fieldValuePtr != NULL) {
  265. X        char *fieldValue;
  266. X
  267. X        fieldValue = ckalloc (valueSize + 1);
  268. X        strncpy (fieldValue, value, valueSize);
  269. X        fieldValue [valueSize] = '\0';
  270. X        *fieldValuePtr = fieldValue;
  271. X    }
  272. X    return TCL_OK;  /* Found! */
  273. X
  274. X}
  275. X
  276. X/*
  277. X *----------------------------------------------------------------------
  278. X *
  279. X * Tcl_SetKeyedListField --
  280. X *   Set a field value in keyed list.
  281. X *
  282. X * Parameters:
  283. X *   o interp (I/O) - Error message will be return in result if there is an
  284. X *     error.
  285. X *   o fieldName (I) - The name of the field to set.
  286. X *   o fieldValue (I) - The value to set for the field.
  287. X *   o keyedList (I) - The keyed list to set a field value in, may be an
  288. X *     NULL or an empty list to create a new keyed list.
  289. X * Results:
  290. X *   A pointer to a dynamically allocated string, or NULL if an error
  291. X *   occured.
  292. X *----------------------------------------------------------------------
  293. X */
  294. Xchar *
  295. XTcl_SetKeyedListField (interp, fieldName, fieldValue, keyedList)
  296. X    Tcl_Interp  *interp;
  297. X    CONST char  *fieldName;
  298. X    CONST char  *fieldValue;
  299. X    CONST char  *keyedList;
  300. X{
  301. X    char   *newField, *newList;
  302. X    int     listArgc, fieldIdx;
  303. X    char  **listArgv = NULL;
  304. X    char   *newArgv [2];
  305. X
  306. X    if (fieldName == '\0') {
  307. X        Tcl_AppendResult (interp, "null key not allowed", (char *) NULL);
  308. X        return NULL;
  309. X    }
  310. X
  311. X    /*
  312. X     * Build a list out of the new key/value pair, we may need it soon.
  313. X     */
  314. X    newArgv [0] = (char *) fieldName;
  315. X    newArgv [1] = (char *) fieldValue;
  316. X    newField = Tcl_Merge (2, newArgv);
  317. X
  318. X    if (keyedList == NULL)
  319. X        keyedList = "";
  320. X
  321. X    /*
  322. X     * Parse the keyed list into an argv and search for the key/value pair.
  323. X     */
  324. X    if (Tcl_SplitList (interp, (char *) keyedList, &listArgc, 
  325. X                       &listArgv) != TCL_OK)
  326. X        goto errorExit;
  327. X
  328. X    if (FindKeyListField (interp, (char *) fieldName, listArgc, listArgv, 
  329. X                          &fieldIdx) != TCL_OK)
  330. X        goto errorExit;
  331. X
  332. X    /*
  333. X     * If the field does not current exist in the keyed list, append it,
  334. X     * otherwise replace it.
  335. X     */
  336. X    if (fieldIdx == -1) {
  337. X        fieldIdx = listArgc;
  338. X        listArgc++;
  339. X    }
  340. X
  341. X    listArgv [fieldIdx] = newField;
  342. X    newList = Tcl_Merge (listArgc, listArgv);
  343. X
  344. X    ckfree ((char *) newField);
  345. X    ckfree ((char *) listArgv);
  346. X    return newList;
  347. X
  348. XerrorExit:
  349. X    ckfree ((char *) newField);
  350. X    if (listArgv != NULL)
  351. X        ckfree ((char *) listArgv);
  352. X    return NULL;
  353. X}
  354. X
  355. X/*
  356. X *----------------------------------------------------------------------
  357. X *
  358. X * Tcl_DeleteKeyedListField --
  359. X *   Delete a field value in keyed list.
  360. X *
  361. X * Parameters:
  362. X *   o interp (I/O) - Error message will be return in result if there is an
  363. X *     error.
  364. X *   o fieldName (I) - The name of the field to set.
  365. X *   o fieldValue (I) - The value to set for the field.
  366. X *   o keyedList (I) - The keyed list to set a field value in, may be an
  367. X *     NULL or an empty list to create a new keyed list.
  368. X * Results:
  369. X *   A pointer to a dynamically allocated string, or NULL if an error
  370. X *   occured.
  371. X *----------------------------------------------------------------------
  372. X */
  373. Xchar *
  374. XTcl_DeleteKeyedListField (interp, fieldName, keyedList)
  375. X    Tcl_Interp  *interp;
  376. X    CONST char  *fieldName;
  377. X    CONST char  *keyedList;
  378. X{
  379. X    char  *newList;
  380. X    int    listArgc, fieldIdx, idx;
  381. X    char **listArgv;
  382. X
  383. X    if (fieldName == '\0') {
  384. X        Tcl_AppendResult (interp, "null key not allowed", (char *) NULL);
  385. X        return NULL;
  386. X    }
  387. X
  388. X    if (Tcl_SplitList (interp, (char *) keyedList, &listArgc, 
  389. X                       &listArgv) != TCL_OK)
  390. X        return NULL;
  391. X
  392. X    if (FindKeyListField (interp, (char *) fieldName, listArgc, listArgv, 
  393. X                          &fieldIdx) != TCL_OK)
  394. X        goto errorExit;
  395. X
  396. X    if (fieldIdx == -1) {
  397. X        Tcl_AppendResult (interp, "field name not found: \"",  fieldName, 
  398. X                          "\"", (char *) NULL);
  399. X        goto errorExit;
  400. X    }
  401. X
  402. X    /*
  403. X     * Move all entries in the argv following the one being deleted, up one
  404. X     * spot.
  405. X     */
  406. X    for (idx = fieldIdx; idx < listArgc; idx++)
  407. X        listArgv [idx] = listArgv [idx + 1];
  408. X    
  409. X    newList = Tcl_Merge (listArgc - 1, listArgv);
  410. X
  411. X    ckfree ((char *) listArgv);
  412. X    return newList;
  413. X
  414. XerrorExit:
  415. X    ckfree ((char *) listArgv);
  416. X    return NULL;
  417. X}
  418. X
  419. X/*
  420. X *----------------------------------------------------------------------
  421. X *
  422. X * Tcl_KeyldelCmd --
  423. X *     Implements the TCL keyldel command:
  424. X *         keyldel listvar key
  425. X *
  426. X * Results:
  427. X *    Standard TCL results.
  428. X *
  429. X *----------------------------------------------------------------------
  430. X */
  431. Xint
  432. XTcl_KeyldelCmd (clientData, interp, argc, argv)
  433. X    ClientData  clientData;
  434. X    Tcl_Interp *interp;
  435. X    int         argc;
  436. X    char      **argv;
  437. X{
  438. X    char  *keyedList, *newList;
  439. X    int    listArgc, fieldIdx, idx;
  440. X    char **listArgv;
  441. X    char  *varPtr;
  442. X
  443. X    if (argc != 3) {
  444. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0],
  445. X                          " listvar key", (char *) NULL);
  446. X        return TCL_ERROR;
  447. X    }
  448. X
  449. X    keyedList = Tcl_GetVar (interp, argv[1], TCL_LEAVE_ERR_MSG);
  450. X    if (keyedList == NULL)
  451. X        return TCL_ERROR;
  452. X
  453. X    newList = Tcl_DeleteKeyedListField (interp, argv [2], keyedList);
  454. X    if (newList == NULL)
  455. X        return TCL_ERROR;
  456. X
  457. X    varPtr = Tcl_SetVar (interp, argv [1], newList, TCL_LEAVE_ERR_MSG);
  458. X    ckfree ((char *) newList);
  459. X
  460. X    return (varPtr == NULL) ? TCL_ERROR : TCL_OK;
  461. X}
  462. X
  463. X/*
  464. X *----------------------------------------------------------------------
  465. X *
  466. X * Tcl_KeylgetCmd --
  467. X *     Implements the TCL keylget command:
  468. X *         keylget listvar key [retvar | {}]
  469. X *
  470. X * Results:
  471. X *    Standard TCL results.
  472. X *
  473. X *----------------------------------------------------------------------
  474. X */
  475. Xint
  476. XTcl_KeylgetCmd (clientData, interp, argc, argv)
  477. X    ClientData  clientData;
  478. X    Tcl_Interp *interp;
  479. X    int         argc;
  480. X    char      **argv;
  481. X{
  482. X    char   *keyedList;
  483. X    char   *fieldValue;
  484. X    char  **fieldValuePtr;
  485. X    int     result;
  486. X
  487. X    if ((argc < 3) || (argc > 4)) {
  488. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0],
  489. X                          " listvar key [retvar | {}]", (char *) NULL);
  490. X        return TCL_ERROR;
  491. X    }
  492. X    if (argv [2] == '\0') {
  493. X        Tcl_AppendResult (interp, "null key not allowed", (char *) NULL);
  494. X        return TCL_ERROR;
  495. X    }
  496. X    keyedList = Tcl_GetVar (interp, argv[1], TCL_LEAVE_ERR_MSG);
  497. X    if (keyedList == NULL)
  498. X        return TCL_ERROR;
  499. X
  500. X    /*
  501. X     * Recursively extract the field (or sub-field) value.  First determine
  502. X     * if we actually need a value.
  503. X     */
  504. X    if ((argc == 4) && (argv [3][0] == '\0'))
  505. X        fieldValuePtr = NULL;
  506. X    else
  507. X        fieldValuePtr = &fieldValue;
  508. X
  509. X    result = Tcl_GetKeyedListField (interp, argv [2], keyedList,
  510. X                                    fieldValuePtr);
  511. X    if (result == TCL_ERROR)
  512. X        return TCL_ERROR;
  513. X
  514. X    /*
  515. X     * Handle field name not found.
  516. X     */
  517. X    if (result == TCL_BREAK) {
  518. X        if (argc == 3) {
  519. X            Tcl_AppendResult (interp, "key \"", argv [2], 
  520. X                              "\" not found in keyed list", (char *) NULL);
  521. X            return TCL_ERROR;
  522. X        } else {
  523. X            interp->result = "0";
  524. X            return TCL_OK;
  525. X        }
  526. X    }
  527. X
  528. X    /*
  529. X     * Handle field name found and return in the result.
  530. X     */
  531. X    if (argc == 3) {
  532. X        Tcl_SetResult (interp, fieldValue, TCL_DYNAMIC);
  533. X        return TCL_OK;
  534. X    }
  535. X
  536. X    /*
  537. X     * Handle null return variable specified and key was found.
  538. X     */
  539. X    if (argv [3][0] == '\0') {
  540. X        interp->result = "1";
  541. X        return TCL_OK;
  542. X    }
  543. X
  544. X    /*
  545. X     * Handle returning the value to the variable.
  546. X     */
  547. X    if (Tcl_SetVar (interp, argv [3], fieldValue, TCL_LEAVE_ERR_MSG) == NULL)
  548. X        result = TCL_ERROR;
  549. X    else
  550. X        result = TCL_OK;
  551. X    ckfree (fieldValue);
  552. X    interp->result = "1";
  553. X    return result;
  554. X}
  555. X
  556. X/*
  557. X *----------------------------------------------------------------------
  558. X *
  559. X * Tcl_KeylsetCmd --
  560. X *     Implements the TCL keylset command:
  561. X *         keylset listvar key value
  562. X *
  563. X * Results:
  564. X *    Standard TCL results.
  565. X *
  566. X *----------------------------------------------------------------------
  567. X */
  568. Xint
  569. XTcl_KeylsetCmd (clientData, interp, argc, argv)
  570. X    ClientData  clientData;
  571. X    Tcl_Interp *interp;
  572. X    int         argc;
  573. X    char      **argv;
  574. X{
  575. X    char *keyedList, *newList;
  576. X    char *varPtr;
  577. X
  578. X    if (argc != 4) {
  579. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0],
  580. X                          " listvar key value", (char *) NULL);
  581. X        return TCL_ERROR;
  582. X    }
  583. X
  584. X    keyedList = Tcl_GetVar (interp, argv[1], 0);
  585. X
  586. X    newList = Tcl_SetKeyedListField (interp, argv [2], argv [3], keyedList);
  587. X    if (newList == NULL)
  588. X        return TCL_ERROR;
  589. X    
  590. X    varPtr = Tcl_SetVar (interp, argv [1], newList, TCL_LEAVE_ERR_MSG);
  591. X    ckfree ((char *) newList);
  592. X
  593. X    return (varPtr == NULL) ? TCL_ERROR : TCL_OK;
  594. X}
  595. X
  596. X/*
  597. X *----------------------------------------------------------------------
  598. X *
  599. X * Tcl_LvarpopCmd --
  600. X *     Implements the TCL replace command:
  601. X *         lvarpop var [index [string]]
  602. X *
  603. X * Results:
  604. X *      Standard TCL results.
  605. X *
  606. X *----------------------------------------------------------------------
  607. X */
  608. Xint
  609. XTcl_LvarpopCmd (clientData, interp, argc, argv)
  610. X    ClientData  clientData;
  611. X    Tcl_Interp *interp;
  612. X    int         argc;
  613. X    char      **argv;
  614. X{
  615. X    int        myargc, result;
  616. X    char     **myargv;
  617. X    char      *varcontents;
  618. X    unsigned   listIdx, idx;
  619. X    char      *resultList;
  620. X
  621. X    if ((argc < 2) || (argc > 4)) {
  622. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], 
  623. X                          " var [index [string]]", (char *) NULL);
  624. X        return TCL_ERROR;
  625. X    }
  626. X
  627. X    varcontents = Tcl_GetVar (interp, argv[1], TCL_LEAVE_ERR_MSG);
  628. X    if (varcontents == NULL)
  629. X        return TCL_ERROR;
  630. X
  631. X    if (Tcl_SplitList (interp, varcontents, &myargc, &myargv) == TCL_ERROR) {
  632. X        result = TCL_ERROR;
  633. X        goto exitPoint;
  634. X    }
  635. X    if (argc == 2) 
  636. X        listIdx = 0;
  637. X    else
  638. X        if (Tcl_GetUnsigned (interp, argv[2], &listIdx) != TCL_OK) {
  639. X            result = TCL_ERROR;
  640. X            goto exitPoint;
  641. X        }
  642. X
  643. X    /*
  644. X     * This is dangerous, but this is like the standard Tcl commands.
  645. X     */
  646. X    if (listIdx >= myargc) {
  647. X        result = TCL_OK;
  648. X        goto exitPoint;
  649. X    }
  650. X    Tcl_SetResult (interp, myargv[listIdx], TCL_VOLATILE);
  651. X
  652. X    if (argc == 4)
  653. X        myargv [listIdx] = argv[3];
  654. X    else {
  655. X        myargc--;
  656. X        for (idx = listIdx; idx < myargc; idx++)
  657. X            myargv [idx] = myargv[idx+1];
  658. X    }
  659. X
  660. X    resultList = Tcl_Merge(myargc, myargv);
  661. X    if (Tcl_SetVar (interp, argv[1], resultList, TCL_LEAVE_ERR_MSG) == NULL)
  662. X        result = TCL_ERROR;
  663. X    else
  664. X        result = TCL_OK;
  665. X    ckfree (resultList);
  666. X
  667. XexitPoint:
  668. X    ckfree((char *) myargv);
  669. X    return result;
  670. X}
  671. X
  672. X/*
  673. X *----------------------------------------------------------------------
  674. X *
  675. X * Tcl_LemptyCmd --
  676. X *     Implements the strcat TCL command:
  677. X *         lempty list
  678. X *
  679. X * Results:
  680. X *     Standard TCL result.
  681. X *
  682. X *----------------------------------------------------------------------
  683. X */
  684. Xint
  685. XTcl_LemptyCmd (clientData, interp, argc, argv)
  686. X    ClientData   clientData;
  687. X    Tcl_Interp  *interp;
  688. X    int          argc;
  689. X    char       **argv;
  690. X{
  691. X    char *scanPtr;
  692. X
  693. X    if (argc != 2) {
  694. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], " list",
  695. X                          (char *) NULL);
  696. X        return TCL_ERROR;
  697. X    }
  698. X
  699. X    scanPtr = argv [1];
  700. X    while ((*scanPtr != '\0') && (isspace (*scanPtr)))
  701. X        scanPtr++;
  702. X    sprintf (interp->result, "%d", (*scanPtr == '\0'));
  703. X    return TCL_OK;
  704. X
  705. X} /* Tcl_LemptyCmd */
  706. END_OF_FILE
  707. if test 19858 -ne `wc -c <'extended/src/list.c'`; then
  708.     echo shar: \"'extended/src/list.c'\" unpacked with wrong size!
  709. fi
  710. # end of 'extended/src/list.c'
  711. fi
  712. if test -f 'extended/src/signal.c' -a "${1}" != "-c" ; then 
  713.   echo shar: Will not clobber existing file \"'extended/src/signal.c'\"
  714. else
  715. echo shar: Extracting \"'extended/src/signal.c'\" \(20540 characters\)
  716. sed "s/^X//" >'extended/src/signal.c' <<'END_OF_FILE'
  717. X/*
  718. X * signal.c --
  719. X *
  720. X * Tcl Unix signal support routines and the signal and trap commands.
  721. X *---------------------------------------------------------------------------
  722. X * Copyright 1991 Karl Lehenbauer and Mark Diekhans.
  723. X *
  724. X * Permission to use, copy, modify, and distribute this software and its
  725. X * documentation for any purpose and without fee is hereby granted, provided
  726. X * that the above copyright notice appear in all copies.  Karl Lehenbauer and
  727. X * Mark Diekhans make no representations about the suitability of this
  728. X * software for any purpose.  It is provided "as is" without express or
  729. X * implied warranty.
  730. X */
  731. X
  732. X#include "tclExtdInt.h"
  733. X
  734. X
  735. X#ifndef SIGCLD
  736. X#   define SIGCLD SIGCHLD
  737. X#endif
  738. X#ifndef SIGCHLD
  739. X#   define SIGCHLD SIGCLD
  740. X#endif
  741. X
  742. X#ifndef MAXSIG
  743. X#    define MAXSIG 32
  744. X#endif
  745. X
  746. X/*
  747. X * Signal name table maps name to number.
  748. X */
  749. X
  750. X#define SIG_NAME_MAX 7
  751. X
  752. Xstatic struct {char *name;
  753. X        short num;
  754. X       } sigNameTable [] = {
  755. X    "HUP",     SIGHUP,
  756. X    "INT",     SIGINT,
  757. X    "QUIT",    SIGQUIT,
  758. X    "ILL",     SIGILL,
  759. X    "TRAP",    SIGTRAP,
  760. X    "IOT",     SIGIOT,
  761. X#ifdef SIGABRT
  762. X    "ABRT",    SIGABRT,
  763. X#endif
  764. X    "EMT",     SIGEMT,
  765. X    "FPE",     SIGFPE,
  766. X    "KILL",    SIGKILL,
  767. X    "BUS",     SIGBUS,
  768. X    "SEGV",    SIGSEGV,
  769. X    "SYS",     SIGSYS,
  770. X    "PIPE",    SIGPIPE,
  771. X    "ALRM",    SIGALRM,
  772. X    "TERM",    SIGTERM,
  773. X    "USR1",    SIGUSR1,
  774. X    "USR2",    SIGUSR2,
  775. X    "CLD",     SIGCLD,
  776. X    "CHLD",    SIGCHLD,
  777. X#ifdef SIGPWR
  778. X    "PWR",     SIGPWR,
  779. X#endif
  780. X#ifdef SIGPOLL
  781. X    "POLL",    SIGPOLL,
  782. X#endif
  783. X#ifdef SIGSTOP
  784. X    "STOP",    SIGSTOP,
  785. X#endif
  786. X#ifdef SIGTSTP
  787. X    "TSTP",    SIGTSTP,
  788. X#endif
  789. X#ifdef SIGCONT
  790. X    "CONT",    SIGCONT,
  791. X#endif
  792. X#ifdef SIGTTIN
  793. X    "TTIN",    SIGTTIN,
  794. X#endif
  795. X#ifdef SIGTTOU
  796. X    "TTOU",    SIGTTOU,
  797. X#endif
  798. X    NULL,         -1};
  799. X
  800. X#ifdef TCL_SIG_PROC_INT
  801. X#   define SIG_PROC_TYPE int
  802. X#else
  803. X#   define SIG_PROC_TYPE void
  804. X#endif
  805. X
  806. X/*
  807. X * Globals that indicate if we got a signal and which ones we got.
  808. X */
  809. Xstatic int           recievedSignal = FALSE;
  810. Xstatic unsigned char signalsRecieved [MAXSIG];
  811. X
  812. X/*
  813. X * Table of commands to evaluate when a signal occurs.  If the command is
  814. X * NULL and the signal is recieved, an error is returned.
  815. X */
  816. Xstatic char *signalTrapCmds [MAXSIG];
  817. X
  818. X/*
  819. X * Prototypes of internal functions.
  820. X */
  821. X
  822. XSIG_PROC_TYPE (*
  823. XGetSignalState _ANSI_ARGS_((int signalNum)));
  824. X
  825. Xint
  826. XSetSignalAction _ANSI_ARGS_((int             signalNum,
  827. X                             SIG_PROC_TYPE (*sigFunc)()));
  828. X
  829. Xstatic SIG_PROC_TYPE
  830. XTclSignalTrap _ANSI_ARGS_((int signalNum));
  831. X
  832. Xstatic int
  833. XEvalTrapCode _ANSI_ARGS_((Tcl_Interp *interp,
  834. X                          int         signalNum,
  835. X                          char       *command));
  836. X
  837. Xstatic int
  838. XParseSignalList _ANSI_ARGS_((Tcl_Interp *interp,
  839. X                             char       *signalListStr,
  840. X                             int         signalList []));
  841. X
  842. Xstatic void
  843. XSignalCmdCleanUp _ANSI_ARGS_((ClientData clientData));
  844. X
  845. X
  846. X/*
  847. X *----------------------------------------------------------------------
  848. X *
  849. X * Tcl_SigNameToNum --
  850. X *     Converts a UNIX signal name to its number, returns -1 if not found.
  851. X *     the name may be upper or lower case and may optionally have the 
  852. X *     leading "SIG" omitted.
  853. X *
  854. X *----------------------------------------------------------------------
  855. X */
  856. Xint
  857. XTcl_SigNameToNum (sigName)
  858. X    char *sigName;
  859. X{
  860. X    char  sigNameUp [SIG_NAME_MAX+1];  /* Upshifted signal name */
  861. X    char *sigNamePtr; 
  862. X    int   idx;
  863. X
  864. X    /*
  865. X     * Copy and upshift requested name.
  866. X     */
  867. X
  868. X    if (strlen (sigName) > SIG_NAME_MAX)
  869. X        return -1;   /* Name too long */
  870. X
  871. X    Tcl_UpShift (sigNameUp, sigName);
  872. X
  873. X    if (STRNEQU (sigNameUp, "SIG", 3))
  874. X        sigNamePtr = &sigNameUp [3];
  875. X    else
  876. X        sigNamePtr = sigNameUp;
  877. X
  878. X    for (idx = 0; sigNameTable [idx].num != -1; idx++)
  879. X        if (STREQU (sigNamePtr, sigNameTable [idx].name))
  880. X            break;
  881. X
  882. X    return sigNameTable [idx].num;
  883. X}
  884. X
  885. X/*
  886. X *----------------------------------------------------------------------
  887. X *
  888. X * GetSignalState --
  889. X *     Get the current state of the specified signal.
  890. X * Parameters:
  891. X *   o signalNum (I) - Signal number to query.
  892. X * Results
  893. X *   The signal function or SIG_DFL or SIG_IGN.  If an error occures,
  894. X *   SIG_ERR is returned (check errno);
  895. X *----------------------------------------------------------------------
  896. X */
  897. Xstatic SIG_PROC_TYPE (*
  898. XGetSignalState (signalNum))
  899. X    int signalNum;
  900. X{
  901. X#ifdef TCL_POSIX_SIG
  902. X    struct sigaction currentState;
  903. X
  904. X    if (sigaction (signalNum, NULL, ¤tState) < 0)
  905. X        return SIG_ERR;
  906. X    return currentState.sa_handler;
  907. X#else
  908. X    SIG_PROC_TYPE  (*actionFunc)();
  909. X
  910. X    if (signalNum == SIGKILL)
  911. X        return SIG_DFL;
  912. X
  913. X    actionFunc = signal (signalNum, SIG_DFL);
  914. X    if (actionFunc == SIG_ERR)
  915. X        return SIG_ERR;
  916. X    if (actionFunc != SIG_DFL)
  917. X        signal (signalNum, actionFunc);  /* reset */
  918. X    return actionFunc;
  919. X#endif
  920. X}
  921. X
  922. X/*
  923. X *----------------------------------------------------------------------
  924. X *
  925. X * SetSignalAction --
  926. X *     Set the action to occur when a signal is received.
  927. X * Parameters:
  928. X *   o signalNum (I) - Signal number to query.
  929. X *   o sigFunc (O) - The signal function or SIG_DFL or SIG_IGN.
  930. X * Results
  931. X *   TRUE if ok,  FALSE if an error (check errno).
  932. X *----------------------------------------------------------------------
  933. X */
  934. Xstatic int
  935. XSetSignalAction (signalNum, sigFunc)
  936. X    int             signalNum;
  937. X    SIG_PROC_TYPE (*sigFunc)();
  938. X{
  939. X#ifdef TCL_POSIX_SIG
  940. X    struct sigaction newState;
  941. X    sigset_t         sigUnblockSet;
  942. X    
  943. X    newState.sa_handler = sigFunc;
  944. X    sigfillset (&newState.sa_mask);
  945. X    newState.sa_flags = 0;
  946. X
  947. X    if (sigaction (signalNum, &newState, NULL) < 0)
  948. X        return FALSE;
  949. X
  950. X    sigemptyset (&sigUnblockSet);
  951. X    sigaddset (&sigUnblockSet, signalNum);
  952. X    if (sigprocmask (SIG_UNBLOCK, &sigUnblockSet, NULL) < 0)
  953. X        return FALSE;
  954. X    return TRUE;
  955. X#else
  956. X    if (signal (signalNum, sigFunc) == SIG_ERR)
  957. X        return FALSE;
  958. X    else
  959. X        return TRUE;
  960. X#endif
  961. X}
  962. X
  963. X/*
  964. X *----------------------------------------------------------------------
  965. X *
  966. X * TclSignalTrap --
  967. X *     Trap handler for UNIX signals.  Sets a flag indicating that the
  968. X *     trap has occured, saves the name and rearms the trap.  The flag
  969. X *     will be seen by the interpreter when its safe to trap.
  970. X * Globals:
  971. X *   o recievedSignal (O) - Set to TRUE, to indicate a signal was recieved.
  972. X *   o signalsRecieved (O) - The entry indicating which signal we recieved
  973. X *     will be set to TRUE;
  974. X *----------------------------------------------------------------------
  975. X */
  976. Xstatic SIG_PROC_TYPE
  977. XTclSignalTrap (signalNum)
  978. X    int signalNum;
  979. X{
  980. X    signalsRecieved [signalNum] = TRUE;
  981. X    recievedSignal = TRUE;
  982. X#ifdef TCL_POSIX_SIG
  983. X    if (signalNum != SIGCHLD) {
  984. X        sigset_t sigBlockSet;
  985. X
  986. X        sigemptyset (&sigBlockSet);
  987. X        sigaddset (&sigBlockSet, SIGCHLD);
  988. X        if (sigprocmask (SIG_BLOCK, &sigBlockSet, NULL) < 0)
  989. X            panic ("TclSignalTrap bug");
  990. X    }
  991. X#else
  992. X    if (signalNum != SIGCHLD) {
  993. X        if (SetSignalAction (signalNum, TclSignalTrap) < 0)
  994. X            panic ("TclSignalTrap bug");
  995. X    }
  996. X#endif
  997. X}
  998. X
  999. X/*
  1000. X *----------------------------------------------------------------------
  1001. X *
  1002. X * EvalTrapCode --
  1003. X *     Run code as the result of a signal.  The code will be run in the
  1004. X *     global context, with the symbolic signal name in a global variable.
  1005. X *     signalReceived.  If an error occured, then the result will be
  1006. X *     left in the interp, if no error occured, the result will be reset.
  1007. X * Parameters:
  1008. X *   o interp (I/O) - The interpreter to run the signal in.
  1009. X *   o signalNum (I) - The signal number of the signal that occured.
  1010. X *   o command (I) - The command string to execute.
  1011. X * Return:
  1012. X *   TCL_OK or TCL_ERROR.
  1013. X *----------------------------------------------------------------------
  1014. X */
  1015. Xstatic int
  1016. XEvalTrapCode (interp, signalNum, command)
  1017. X    Tcl_Interp *interp;
  1018. X    int         signalNum;
  1019. X    char       *command;
  1020. X{
  1021. X    Interp        *iPtr = (Interp *) interp;
  1022. X    char          *signalName;
  1023. X    int            result;
  1024. X    CallFrame     *savedVarFramePtr;
  1025. X
  1026. X    Tcl_ResetResult (interp);
  1027. X
  1028. X    /*
  1029. X     * Modify the interpreter state to execute in the global frame.
  1030. X     */
  1031. X    savedVarFramePtr = iPtr->varFramePtr;
  1032. X    iPtr->varFramePtr = NULL;
  1033. X
  1034. X    /*
  1035. X     * Force name to always be SIGCHLD, even if system defines only SIGCLD.
  1036. X     */
  1037. X    if (signalNum == SIGCHLD)
  1038. X        signalName = "SIGCHLD";
  1039. X    else
  1040. X        signalName = Tcl_SignalId (signalNum);
  1041. X
  1042. X    if (Tcl_SetVar (interp, "signalRecieved", signalName,
  1043. X                    TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL)
  1044. X        result = TCL_ERROR;
  1045. X    else
  1046. X        result = TCL_OK;
  1047. X    if (result == TCL_OK);
  1048. X        result = Tcl_Eval (interp, signalTrapCmds [signalNum], 0, NULL);
  1049. X
  1050. X    /*
  1051. X     * Restore the frame pointer and return the result (only OK or ERROR).
  1052. X     */
  1053. X    iPtr->varFramePtr = savedVarFramePtr;
  1054. X
  1055. X    if (result == TCL_ERROR) {
  1056. X        char errorInfo [TCL_RESULT_SIZE];
  1057. X
  1058. X        sprintf (errorInfo, "\n    while executing signal trap code for %s%s",
  1059. X                 signalName, " signal");
  1060. X        Tcl_AddErrorInfo (interp, errorInfo);
  1061. X
  1062. X        return TCL_ERROR;
  1063. X    } else {
  1064. X        Tcl_ResetResult (interp);
  1065. X        return TCL_OK;
  1066. X    }
  1067. X}
  1068. X
  1069. X/*
  1070. X *----------------------------------------------------------------------
  1071. X *
  1072. X * Tcl_ResetSignals --
  1073. X *  
  1074. X *   Reset all of the signal flags to indicate that no signals have 
  1075. X * occured.  This is used by the shell at the beginning of each interactive
  1076. X * command
  1077. X *
  1078. X * Globals:
  1079. X *   o recievedSignal (O) - Will be cleared.
  1080. X *   o signalsRecieved (O) - The indicates which signal where recieved.
  1081. X *----------------------------------------------------------------------
  1082. X */
  1083. Xvoid
  1084. XTcl_ResetSignals ()
  1085. X{
  1086. X    int  signalNum;
  1087. X
  1088. X    recievedSignal = FALSE;
  1089. X    for (signalNum = 0; signalNum < MAXSIG; signalNum++) 
  1090. X        signalsRecieved [signalNum] = FALSE;
  1091. X
  1092. X}
  1093. X
  1094. X/*
  1095. X *----------------------------------------------------------------------
  1096. X *
  1097. X * Tcl_CheckForSignal --
  1098. X *  
  1099. X *   Called by Tcl_Eval to check if a signal was received when Tcl_Eval is in
  1100. X * a safe state.  If the signal was received, this handles processing the
  1101. X * signal prehaps recursively eval-ing some code.  This is called just after a
  1102. X * command completes.  The results of the command are passed to this procedure
  1103. X * and may be altered by it.  If trap code is specified for the signal that
  1104. X * was recieved, then the trap will be executed, otherwise an error result
  1105. X * will be returned indicating that the signal occured.
  1106. X * 
  1107. X * Parameters:
  1108. X *   o interp (I/O) - Interp->result should contain the result for
  1109. X *     the command that just executed.  This will either be restored or
  1110. X *     replaced with a new result.
  1111. X *   o cmdResultCode (I) - The integer result returned by the command that
  1112. X *     Tcl_Eval just completed.
  1113. X * Globals:
  1114. X *   o recievedSignal (O) - Will be cleared.
  1115. X *   o signalsRecieved (O) - The indicates which signal where recieved.
  1116. X * Returns:
  1117. X *   Either the original result core, an error result if one of the
  1118. X *   trap commands returned an error, or an error indicating the
  1119. X *   a signal occured.
  1120. X *----------------------------------------------------------------------
  1121. X */
  1122. Xint
  1123. XTcl_CheckForSignal (interp, cmdResultCode)
  1124. X    Tcl_Interp *interp;
  1125. X    int         cmdResultCode;
  1126. X{
  1127. X    char   *savedResult;
  1128. X    int     signalNum, result, retErrorForSignal = -1;
  1129. X
  1130. X    if (!recievedSignal)
  1131. X        return cmdResultCode;  /* Not signal recieved */
  1132. X
  1133. X    savedResult = ckalloc (strlen (interp->result) + 1);
  1134. X    strcpy (savedResult, interp->result);
  1135. X    Tcl_ResetResult (interp);
  1136. X
  1137. X    for (signalNum = 1; signalNum < MAXSIG; signalNum++) {
  1138. X        if (signalsRecieved [signalNum]) {
  1139. X            signalsRecieved [signalNum] = FALSE;
  1140. X            if (signalTrapCmds [signalNum] == NULL)
  1141. X                retErrorForSignal = signalNum;
  1142. X            else {
  1143. X                result = EvalTrapCode (interp, signalNum,
  1144. X                                       signalTrapCmds [signalNum]);
  1145. X                if (result == TCL_ERROR)
  1146. X                    goto exitPoint;
  1147. X            }
  1148. X        }
  1149. X    }
  1150. X
  1151. X    if (retErrorForSignal >= 0) {
  1152. X        char *signalName;
  1153. X
  1154. X        /*
  1155. X         * Force name to always be SIGCHLD, even if system defines only SIGCLD.
  1156. X         */
  1157. X        if (retErrorForSignal == SIGCHLD)
  1158. X            signalName = "SIGCHLD";
  1159. X        else
  1160. X            signalName = Tcl_SignalId (retErrorForSignal);
  1161. X
  1162. X        Tcl_SetErrorCode (interp, "UNIX SIG ", signalName, (char*) NULL);
  1163. X        Tcl_AppendResult (interp, signalName, " signal received", 
  1164. X                          (char *)NULL);
  1165. X        result = TCL_ERROR;
  1166. X    } else {
  1167. X        Tcl_SetResult (interp, savedResult, TCL_DYNAMIC);
  1168. X        savedResult = NULL;
  1169. X        result = cmdResultCode;
  1170. X    }
  1171. X
  1172. XexitPoint:
  1173. X    if (savedResult != NULL)
  1174. X        ckfree (savedResult);
  1175. X    /*
  1176. X     * An error might have caused clearing of some signal flags to be missed.
  1177. X     */
  1178. X    Tcl_ResetSignals ();
  1179. X    return result;
  1180. X}
  1181. X
  1182. X/*
  1183. X *----------------------------------------------------------------------
  1184. X *
  1185. X * ParseSignalList --
  1186. X *  
  1187. X *   Parse a list of signal names or numbers.
  1188. X * 
  1189. X * Parameters:
  1190. X *   o interp (O) - Interpreter for returning errors.
  1191. X *   o signalListStr (I) - The Tcl list of signals to convert.
  1192. X *   o signalList (O) - The list of converted signal numbers, must be
  1193. X *     big enough to hold MAXSIG signals.
  1194. X *     Tcl_Eval just completed.
  1195. X * Returns:
  1196. X *   The number of signals converted, or -1 if an error occures.
  1197. X *----------------------------------------------------------------------
  1198. X */
  1199. Xstatic int
  1200. XParseSignalList (interp, signalListStr, signalList)
  1201. X    Tcl_Interp *interp;
  1202. X    char       *signalListStr;
  1203. X    int         signalList [];
  1204. X{
  1205. X    char         **signalListArgv;
  1206. X    int            signalListSize, signalNum, idx;
  1207. X    int            result = -1;
  1208. X    char          *signalName;
  1209. X
  1210. X    if (Tcl_SplitList (interp, signalListStr, &signalListSize, 
  1211. X                       &signalListArgv) != TCL_OK)
  1212. X        return -1;
  1213. X
  1214. X    if (signalListSize > MAXSIG) {
  1215. X        Tcl_AppendResult (interp, "too many signals supplied in list",
  1216. X                          (char *) NULL);
  1217. X        goto exitPoint;
  1218. X    }
  1219. X
  1220. X    if (signalListSize == 0) {
  1221. X        Tcl_AppendResult (interp, "signal list may not be empty",
  1222. X                          (char *) NULL);
  1223. X        goto exitPoint;
  1224. X    }
  1225. X
  1226. X    for (idx = 0; idx < signalListSize; idx++) {
  1227. X        signalName = signalListArgv [idx];
  1228. X
  1229. X        if (Tcl_StrToInt (signalName, 0, &signalNum))
  1230. X            signalName = Tcl_SignalId (signalNum);
  1231. X        else
  1232. X            signalNum = Tcl_SigNameToNum (signalName);
  1233. X
  1234. X        if (signalName == NULL) {
  1235. X            char numBuf [20];
  1236. X
  1237. X            sprintf (numBuf, "%d", signalNum);
  1238. X            Tcl_AppendResult (interp, "invalid signal number: ",
  1239. X                              numBuf, (char *) NULL);
  1240. X            goto exitPoint;
  1241. X        }
  1242. X
  1243. X        if ((signalNum < 1) || (signalNum > NSIG)) {
  1244. X            Tcl_AppendResult (interp, "invalid signal name: ",
  1245. X                              signalName, (char *) NULL);
  1246. X            goto exitPoint;
  1247. X        }
  1248. X        signalList [idx] = signalNum;
  1249. X    }
  1250. X
  1251. X    result = signalListSize;
  1252. XexitPoint:
  1253. X    ckfree ((char *) signalListArgv);
  1254. X    return result;
  1255. X
  1256. X}
  1257. X
  1258. X/*
  1259. X *----------------------------------------------------------------------
  1260. X *
  1261. X * Tcl_SignalCmd --
  1262. X *     Implements the TCL signal command:
  1263. X *         signal action siglist [command]
  1264. X *
  1265. X * Results:
  1266. X *      Standard TCL results, may return the UNIX system error message.
  1267. X *
  1268. X * Side effects:
  1269. X *
  1270. X *----------------------------------------------------------------------
  1271. X */
  1272. Xstatic int
  1273. XTcl_SignalCmd (clientData, interp, argc, argv)
  1274. X    char       *clientData;
  1275. X    Tcl_Interp *interp;
  1276. X    int         argc;
  1277. X    char      **argv;
  1278. X{
  1279. X    int            signalListSize, signalNum, idx;
  1280. X    int            signalList [MAXSIG];
  1281. X    char          *signalName;
  1282. X    SIG_PROC_TYPE  (*actionFunc)();
  1283. X    int            commandLen = -1;
  1284. X
  1285. X    if ((argc < 3) || (argc > 4)) {
  1286. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], 
  1287. X                          " action signalList [commands]", (char *) NULL);
  1288. X        return TCL_ERROR;
  1289. X    }
  1290. X
  1291. X    signalListSize = ParseSignalList (interp, argv [2], signalList);
  1292. X    if (signalListSize < 0)    
  1293. X        return TCL_ERROR;
  1294. X
  1295. X    /*
  1296. X     * Determine the action to take on all of the signals.
  1297. X     */
  1298. X    if (STREQU (argv [1], "trap")) {
  1299. X        actionFunc = TclSignalTrap;
  1300. X        if (argc != 4) {
  1301. X            Tcl_AppendResult (interp, argv[0], ": command required for ",
  1302. X                             "trapping signals", (char *) NULL);
  1303. X            return TCL_ERROR;
  1304. X        }
  1305. X        commandLen = strlen (argv [3]);
  1306. X    } else {
  1307. X        if (STREQU (argv [1], "default")) {
  1308. X            actionFunc = SIG_DFL;
  1309. X        } else if (STREQU (argv [1], "ignore")) {
  1310. X            actionFunc = SIG_IGN;
  1311. X        } else if (STREQU (argv [1], "error")) {
  1312. X            actionFunc = TclSignalTrap;
  1313. X        } else if (!STREQU (argv [1], "get")) {
  1314. X            Tcl_AppendResult (interp, "invalid signal action specified: ", 
  1315. X                              argv [1], ": expected one of \"default\", ",
  1316. X                              "\"ignore\", \"error\", \"trap\", or \"get\"",
  1317. X                              (char *) NULL);
  1318. X            return TCL_ERROR;
  1319. X        }
  1320. X    }
  1321. X
  1322. X    /*
  1323. X     * Either get or set the signals.
  1324. X     */
  1325. X    if (argv [1][0] == 'g') {
  1326. X        char *actionList [MAXSIG];
  1327. X        
  1328. X        for (idx = 0; idx < signalListSize; idx ++) {
  1329. X            signalNum = signalList [idx];
  1330. X
  1331. X            actionFunc = GetSignalState (signalNum);
  1332. X            if (actionFunc == SIG_ERR)
  1333. X                goto unixSigError;
  1334. X
  1335. X            if (actionFunc == SIG_DFL) 
  1336. X                actionList [idx] = "default";
  1337. X            else if (actionFunc == SIG_IGN)
  1338. X                actionList [idx] = "ignore";
  1339. X            else if (actionFunc == TclSignalTrap) {
  1340. X                if (signalTrapCmds [signalNum] == NULL)
  1341. X                    actionList [idx] = "error";
  1342. X                else
  1343. X                    actionList [idx] = "trap";
  1344. X            }
  1345. X        }
  1346. X        Tcl_SetResult (interp, Tcl_Merge (signalListSize, actionList),
  1347. X                       TCL_DYNAMIC);
  1348. X    } else {
  1349. X        for (idx = 0; idx < signalListSize; idx ++) {
  1350. X            signalNum = signalList [idx];
  1351. X
  1352. X            if (signalTrapCmds [signalNum] != NULL) {
  1353. X                ckfree (signalTrapCmds [signalNum]);
  1354. X                signalTrapCmds [signalNum] = NULL;
  1355. X            }
  1356. X            if (!SetSignalAction (signalNum, actionFunc))
  1357. X                goto unixSigError;
  1358. X
  1359. X            if (commandLen > 0) {
  1360. X                signalTrapCmds [signalNum] = ckalloc (commandLen + 1);
  1361. X                strcpy (signalTrapCmds [signalNum], argv [3]);
  1362. X            }
  1363. X        }
  1364. X    }
  1365. X    return TCL_OK;
  1366. X
  1367. XunixSigError:
  1368. X    Tcl_AppendResult (interp, "error setting or getting signal: ",
  1369. X                      Tcl_UnixError (interp), (char *) NULL);
  1370. X    return TCL_ERROR;
  1371. X}
  1372. X
  1373. X/*
  1374. X *----------------------------------------------------------------------
  1375. X *
  1376. X *  SignalCmdCleanUp --
  1377. X *      Clean up the signal table when the interpreter is deleted.  This
  1378. X *      is actually when the signal command is deleted.  It releases the
  1379. X *      all signal commands that have been allocated.
  1380. X *
  1381. X *----------------------------------------------------------------------
  1382. X */
  1383. Xstatic void
  1384. XSignalCmdCleanUp (clientData)
  1385. X    ClientData clientData;
  1386. X{
  1387. X    int idx;
  1388. X
  1389. X    for (idx = 0; idx < MAXSIG; idx++)
  1390. X        if (signalTrapCmds [idx] != NULL) {
  1391. X            ckfree (signalTrapCmds [idx]);
  1392. X            signalTrapCmds [idx] = NULL;
  1393. X        }
  1394. X
  1395. X}
  1396. X
  1397. X/*
  1398. X *----------------------------------------------------------------------
  1399. X *
  1400. X * Tcl_InitSignalHandling --
  1401. X *      Initializes the TCL unix commands.
  1402. X *
  1403. X * Side effects:
  1404. X *    A catch trap is armed for the SIGINT signal.
  1405. X *
  1406. X *----------------------------------------------------------------------
  1407. X */
  1408. Xvoid
  1409. XTcl_InitSignalHandling (interp)
  1410. X    Tcl_Interp *interp;
  1411. X{
  1412. X    int idx;
  1413. X
  1414. X    for (idx = 0; idx < MAXSIG; idx++) {
  1415. X        signalsRecieved [idx] = FALSE;
  1416. X        signalTrapCmds [idx] = NULL;
  1417. X    }
  1418. X    Tcl_CreateCommand (interp, "signal", Tcl_SignalCmd, (ClientData)NULL,
  1419. X                      SignalCmdCleanUp);
  1420. X    /*
  1421. X     * If interrupt is currently  being trapped, enabled it.  Other wise
  1422. X     * leave it off, or if this process is running as a background job it will
  1423. X     * get its parent's (shell's) signals.
  1424. X     */
  1425. X    if (GetSignalState (SIGINT) != SIG_IGN)
  1426. X        SetSignalAction (SIGINT, TclSignalTrap);
  1427. X}
  1428. X
  1429. END_OF_FILE
  1430. if test 20540 -ne `wc -c <'extended/src/signal.c'`; then
  1431.     echo shar: \"'extended/src/signal.c'\" unpacked with wrong size!
  1432. fi
  1433. # end of 'extended/src/signal.c'
  1434. fi
  1435. echo shar: End of archive 19 \(of 23\).
  1436. cp /dev/null ark19isdone
  1437. MISSING=""
  1438. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ; do
  1439.     if test ! -f ark${I}isdone ; then
  1440.     MISSING="${MISSING} ${I}"
  1441.     fi
  1442. done
  1443. if test "${MISSING}" = "" ; then
  1444.     echo You have unpacked all 23 archives.
  1445.     echo "Now cd to "extended", edit the makefile, then do a "make""
  1446.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1447. else
  1448.     echo You still need to unpack the following archives:
  1449.     echo "        " ${MISSING}
  1450. fi
  1451. ##  End of shell archive.
  1452. exit 0
  1453.  
  1454. exit 0 # Just in case...
  1455. -- 
  1456. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1457. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1458. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1459. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1460.